
package com.ybear.ybcomponent.widget.menu;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.ybear.ybcomponent.ItemStyleBuild;
import com.ybear.ybcomponent.R;
import com.ybear.ybcomponent.RedDotStyleBuild;
import com.ybear.ybcomponent.Utils;
import com.ybear.ybcomponent.widget.RedDotLayout;

import java.util.ArrayList;
import java.util.List;

/**
 * 菜单View
 *
 *
 * 选中当前位置的Item
 * @see #setSelectItem(int)
 *
 * 设置启用小红点
 * @see #setEnableRedDot(boolean)
 *
 * 设置启用小红点
 * @see #setEnableRedDot(boolean)
 *
 * 设置小红点大小
 * @see #setRedDotSize(int)
 *
 * 设置小红点样式
 * @see #setRedDotStyleBuild(RedDotStyleBuild)
 *
 * 获取小红点布局
 * @see #getRedDotLayout(int)
 *
 * 获取ItemView
 * @see #getChildLayout(int)
 *
 * 选中当前位置的Item
 * @see #setSelectItem(int)
 *
 * 获取当前Item的位置
 * @see #getCurrentPosition()
 *
 * 获取之前的Item的位置
 * @see #getOldPosition()
 *
 * 设置菜单Item的Icon
 * @see #setMenuItem(MenuItem...) (Integer[], String...)
 *
 * 设置点击发生改变时的事件监听器
 * @see #setOnCheckedChangeListener(OnCheckedChangeListener)
 *
 * 设置子项样式
 * @see #setItemStyle(ItemStyleBuild)
 *
 */
public class MenuView extends LinearLayout {
    private final List<MenuItem> mMenuItem = new ArrayList<>();
    private int mOldPosition, mCurPosition;
    private int mDividerColor, mTopLineColor;
    private int mDividerHeight;
    private float mDividerWidth, mTopLineWidth;
    private boolean mEnableDivider, mEnableTopLine;
    private boolean mEnableRedDot;
    private int mRedDotSize = -1;

    private Paint mPaint;
    private ItemStyleBuild mItemStyleBuild;
    private RedDotStyleBuild mRedDotStyleBuild;

    @Nullable
    private OnInterceptItemTouchListener mOnInterceptItemTouchListener;
    @Nullable
    private OnCheckedChangeListener mOnCheckedChangeListener;

    public MenuView(Context context) {
        this(context, null);
    }

    public MenuView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void initTypeArray(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MenuView);

        //是否启用子项之间的分割线
        mEnableDivider = typedArray.getBoolean(
                R.styleable.MenuView_menuEnableDivider, false
        );
        //子项之间分割线颜色
        mDividerColor = typedArray.getColor(
                R.styleable.MenuView_menuDividerColor, getResources().getColor( R.color.color75 )
        );
        //子项之间分割线宽度
        mDividerWidth = typedArray.getFloat(R.styleable.MenuView_menuDividerWidth, 1F);
        //子项之间的分割线
        mDividerHeight = typedArray.getDimensionPixelSize(
                R.styleable.MenuView_menuDividerHeight, 0
        );
        //是否启用菜单顶部分割线
        mEnableTopLine = typedArray.getBoolean(
                R.styleable.MenuView_menuEnableTopLine, false
        );
        //菜单顶部分割线的颜色
        mTopLineColor = typedArray.getColor(
                R.styleable.MenuView_menuTopLineColor, getResources().getColor( R.color.color75 )
        );
        //菜单顶部分割线的宽度
        mTopLineWidth = typedArray.getFloat(R.styleable.MenuView_menuTopLineWidth, 1F);
        typedArray.recycle();
    }

    /**
     * 初始化
     */
    private void init(Context context, AttributeSet attrs) {
        initTypeArray(context, attrs);

        mPaint = new Paint();
        setOrientation( HORIZONTAL );
        setGravity( Gravity.CENTER );
        setBackgroundResource( R.color.colorWhite );
        setClipChildren( false );
    }

    @Override
    public void setBackground(Drawable background) {
        super.setBackground(background);
        for (int i = 0; i < getChildCount(); i++) getChildAt( i ).setBackground( background );
    }

    @Override
    public void setBackgroundColor(int color) {
        super.setBackgroundColor(color);
        for (int i = 0; i < getChildCount(); i++) getChildAt( i ).setBackgroundColor( color );
    }

    @Override
    public void setBackgroundResource(int id) {
        super.setBackgroundResource(id);
        for (int i = 0; i < getChildCount(); i++) getChildAt( i ).setBackgroundResource( id );
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        if( mEnableTopLine ) {
            mPaint.setStrokeWidth( mTopLineWidth );
            mPaint.setColor( mTopLineColor );
            canvas.drawLine(0, 0, width, 0, mPaint);
        }

        super.dispatchDraw(canvas);

        if( mEnableDivider ) {
            mPaint.setStrokeWidth( mDividerWidth );
            mPaint.setColor( mDividerColor );
            for (int i = 0; i < getChildCount(); i++) {
                View v = getChildAt( i );
                float startY, stopY;
                int x = v.getLeft();
                if( x == 0 ) continue;
                startY = mDividerHeight == 0 ? 0 : ( height - mDividerHeight ) / 2F;
                stopY = mDividerHeight == 0 ? height : height - startY;
                canvas.drawLine(x, startY, x, stopY, mPaint);
            }
        }
    }

    public MenuView setEnableDivider(boolean enable) {
        mEnableDivider = enable;
        return this;
    }
    public MenuView setDividerColor(@ColorInt int color) {
        mDividerColor = color;
        return this;
    }
    public MenuView setDividerColor(@NonNull Resources res, @ColorRes int color) {
        mDividerColor = res.getColor( color );
        return this;
    }
    public MenuView setDividerWidth(float width) {
        this.mDividerWidth = width;
        return this;
    }
    public MenuView setDividerHeight(int height) {
        this.mDividerHeight = Utils.dp2Px(getContext(), height);
        return this;
    }

    public MenuView setEnableTopLine(boolean mEnableTopLine) {
        this.mEnableTopLine = mEnableTopLine;
        return this;
    }
    public MenuView setTopLineColor(@NonNull Resources res, @ColorRes int color) {
        mTopLineColor = res.getColor( color );
        return this;
    }
    public MenuView setTopLineColor(@ColorInt int color) {
        mTopLineColor = color;
        return this;
    }
    public MenuView setTopLineHeight(float width) {
        this.mTopLineWidth = width;
        return this;
    }

    /**
     * 选中当前位置的Item
     * @param position  位置
     * @param isCall    回调{@link OnCheckedChangeListener#onCheckedChanged(MenuView, View, int, int)}
     *                  false时只切换图标。
     * @return          {@link MenuView}
     */
    public MenuView setSelectItem(int position, boolean isCall) {
        if( mMenuItem == null ) return this;
        View item = getChildAt( position );
        mCurPosition = position;  //选中的位置

        //回调点击改变监听器
        if( isCall && mOnCheckedChangeListener != null ) {
            mOnCheckedChangeListener.onCheckedChanged(
                    this, item, mCurPosition, mOldPosition
            );
        }

        for( int i = 0; i < mMenuItem.size(); i++ ) {
            MenuItem menuItem = mMenuItem.get( i );
            Drawable img;
            int textColor;
            String text;
            int interceptType = InterceptType.NONE;
            /* 如果i与position一致时视为按下操作，如果按下操作没有资源id或文本内容时跳过 */
            ViewGroup vgChildLayout = getChildLayout( i );
            if( i == position ) {
                /* 选中的控件 */
                img = menuItem.getIconOfSelect();
                text = menuItem.getTextOfSelect();
                textColor = menuItem.getItemStyleBuild().getTextSelectColor();
            }else {
                /* 未选中的控件 */
                if( i != mOldPosition ) continue;
                img = menuItem.getIcon();
                text = menuItem.getText();
                textColor = menuItem.getItemStyleBuild().getTextColor();
            }
            //拦截Item
            if( mOnInterceptItemTouchListener != null ) {
                interceptType = mOnInterceptItemTouchListener.onIntercept(
                        this, vgChildLayout, mCurPosition, mOldPosition
                );
            }
            //设置Item点击样式
            setItemTouchStyle( vgChildLayout, img, text, textColor, interceptType );
        }
        //临时保存之前选中的位置
        mOldPosition = mCurPosition;
        postInvalidate();
        return this;
    }

    /**
     * 设置启用小红点
     * 必须在{@link #setMenuItem(MenuItem...)} (Integer[], String...)}之后调用。
     * @param enable    是否启用
     * @return          {@link MenuView}
     */
    public MenuView setEnableRedDot(boolean enable) {
        mEnableRedDot = enable;
        return this;
    }

    /**
     * 设置小红点大小
     * @param size      高度和宽度
     * @return          {@link MenuView}
     */
    public MenuView setRedDotSize(int size) {
        mRedDotSize = size;
        return this;

    }

    /**
     * 设置小红点样式
     * @param build     样式
     * @return          {@link MenuView}
     */
    public MenuView setRedDotStyleBuild(RedDotStyleBuild build) {
        mRedDotStyleBuild = build;
        return this;
    }

    /**
     * 设置子项样式
     * @param build 样式
     */
    public MenuView setItemStyle(ItemStyleBuild build) {
        mItemStyleBuild = build;
        return this;
    }

    /**
     刷新菜单
     */
    public void notifyMenuChanged() {
        if( mMenuItem == null || mMenuItem.size() == 0 ) return;
        for( int i = 0; i < mMenuItem.size(); i++ ) {
            MenuItem item = mMenuItem.get( i );
            RedDotLayout rdl = getRedDotLayout( i );
            if( mItemStyleBuild != null ) item.setItemStyleBuild( mItemStyleBuild );
            if( mRedDotStyleBuild != null ) item.setRedDotStyleBuild( mRedDotStyleBuild );

            if( rdl != null ) {
                rdl.setRedDotStyleBuild( item.getRedDotStyleBuild() );
                if( mRedDotSize >= 0 ) {
                    rdl.setRedDotSize( Utils.dp2Px( getContext(), mRedDotSize ) );
                }
                rdl.setEnableRedDotView( mEnableRedDot );
            }

            ItemStyleBuild itemStyleBuild = item.getItemStyleBuild();
            setImgStyle( getChildViewOfImageView( i ), itemStyleBuild );
            setTextStyle( getChildViewOfTextView( i ), itemStyleBuild );

        }
        requestLayout();
    }

    /**
     * 获取小红点布局
     * @param position  Item下标
     * @return          {@link RedDotLayout}
     */
    @Nullable
    public RedDotLayout getRedDotLayout(int position) {
        if( position < 0 || position >= getChildCount() ) return null;
        return (RedDotLayout) ((FrameLayout) getChildAt( position )).getChildAt( 0 );
    }

    /**
     * 获取ItemView。
     * @param position  Item下标
     * @return          {@link ViewGroup}
     */
    @Nullable
    public ViewGroup getChildLayout(int position) {
        RedDotLayout rdl = getRedDotLayout( position );
        return rdl != null ? (ViewGroup) rdl.getChildAt( 0 ) : null;
    }

    @Nullable
    public ImageView getChildViewOfImageView(int position) {
        ViewGroup vg = getChildLayout( position );
        return vg != null ? (ImageView) vg.getChildAt( 0 ) : null;
    }

    @Nullable
    public TextView getChildViewOfTextView(int position) {
        ViewGroup vg = getChildLayout( position );
        return vg != null ? (TextView) vg.getChildAt( 1 ) : null;
    }

    /**
     * 选中当前位置的Item
     * 该方法会回调{@link OnCheckedChangeListener#onCheckedChanged(MenuView, View, int, int)}
     * @param position  位置
     * @return          {@link MenuView}
     */
    public MenuView setSelectItem(int position) {
        return setSelectItem( position, true );
    }

    /**
     * 获取当前Item的位置
     * @return      位置
     */
    public int getCurrentPosition() { return mCurPosition; }

    /**
     * 获取之前的Item的位置
     * @return      位置
     */
    public int getOldPosition() { return mOldPosition; }

    /**
     获取菜单数量
     @return                数量
     */
    public int getMenuCount() {
        return mMenuItem != null ? mMenuItem.size() : 0;
    }

    /**
     设置选中菜单Item的Icon
     @param items       {@link MenuItem}
     @return            this
     */
    public MenuView setMenuItem(MenuItem... items) {
        mMenuItem.clear();
        if( items == null || items.length == 0 ) return this;
        for( int i = 0; i < items.length; i++ ) {
            MenuItem item = items[ i ];
            View v = createItemView( item.getIcon(), item.getText(), item.getItemStyleBuild() );
            LayoutParams lpItem = new LayoutParams( 0, ViewGroup.LayoutParams.MATCH_PARENT );
            lpItem.weight = 1;
            //添加到父布局
            addView( v, lpItem );
            //设置tag，数据为当前下标
            v.setTag( i );
            //设置item的点击
            setItemOnClick( v );
            mMenuItem.add( item );
        }
        //默认选中第一个
        setSelectItem( 0 );
        return this;
    }

    /**
     Item点击事件拦截器
     Item触发Touch后会调用该监听器，根据返回类型决定拦截的操作
     @param l           监听器
     */
    public void setOnInterceptItemTouchListener(OnInterceptItemTouchListener l) {
        mOnInterceptItemTouchListener = l;
    }

    /**
     * 设置点击发生改变时的事件监听器
     * @param mOnCheckedChangeListener  监听器
     */
    public void setOnCheckedChangeListener(OnCheckedChangeListener mOnCheckedChangeListener) {
        this.mOnCheckedChangeListener = mOnCheckedChangeListener;
    }

    /**
     * 设置item的点击
     * @param view     被设置的点击事件
     */
    private void setItemOnClick(View view) {
        view.setFocusable( true );
        view.setClickable( true );
        //设置Item的点击事件
        view.setOnClickListener(v -> setSelectItem( (int) v.getTag() ) );
    }

    /**
     * 创建图标子项
     * @param drawable  图标
     * @return          {@link LinearLayout}
     */
    private FrameLayout createItemView(Drawable drawable, @Nullable String s, ItemStyleBuild build) {
        FrameLayout flTouchLayout = new FrameLayout( getContext() );
        //小红点布局
        RedDotLayout item = new RedDotLayout( getContext() );
        LinearLayout llLayout = new LinearLayout( getContext() );

        llLayout.setOrientation( LinearLayout.VERTICAL );
        llLayout.setGravity( Gravity.CENTER );
        llLayout.addView( createChildItem( drawable, build ) );
        llLayout.addView( createChildItem( s, build ) );

        LinearLayout.LayoutParams lpLayout = new LinearLayout.LayoutParams(
                LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT
        );
        lpLayout.gravity = Gravity.CENTER;
        llLayout.setLayoutParams( lpLayout );
        llLayout.setClipChildren( false );

        item.addView( llLayout );
        flTouchLayout.addView( item );
        flTouchLayout.setClipChildren( false );

        FrameLayout.LayoutParams lpItem = new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
        );
        lpItem.gravity = Gravity.CENTER;
        item.setLayoutParams( lpItem );
        return flTouchLayout;
    }

    /**
     * 创建图文子控件
     * @param s         文字内容
     * @return          {@link TextView}
     */
    private TextView createChildItem(String s, ItemStyleBuild build) {
        TextView item = new TextView( getContext() );
        item.setLayoutParams( new LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT
        ));
        item.setText( s );
        //设置图文控件样式
        setTextStyle( item, build );
        item.setVisibility( TextUtils.isEmpty( s ) ? GONE : VISIBLE );
        return item;
    }

    /**
     * 创建图标子控件
     * @param drawable   图标
     * @return           {@link ImageView}
     */
    private ImageView createChildItem(Drawable drawable, ItemStyleBuild build) {
        ImageView item = new ImageView(getContext());
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                Utils.dp2Px( getContext(), build.getIconWidth() ),
                Utils.dp2Px( getContext(), build.getIconHeight() )
        );
        item.setLayoutParams( lp );
        if( drawable != null ) item.setImageDrawable( drawable );
        item.setScaleType( ImageView.ScaleType.CENTER_CROP );
        item.setAdjustViewBounds( true );
        //设置图标控件样式
        setImgStyle( item, build );
        return item;
    }

    /**
     * 设置控件按下的样式
     * @param vg             按下的控件{@link #createChildItem(Drawable, ItemStyleBuild)},
     *                              {@link #createChildItem(String, ItemStyleBuild)}
     * @param drawable      图标
     * @param textColor     文本颜色
     */
    private void setItemTouchStyle(ViewGroup vg, Drawable drawable,
                                   String text, @ColorRes int textColor,
                                   int interceptType) {
        if( vg == null || vg.getChildCount() != 2 || interceptType == InterceptType.ALL ) return;

        if( interceptType != InterceptType.IMAGE ) {
            ImageView ivImg = (ImageView) vg.getChildAt( 0 );
            ivImg.setImageDrawable( drawable );
            ivImg.setVisibility( drawable != null ? VISIBLE : GONE );
        }
        if( interceptType != InterceptType.TEXT ) {
            TextView tvText = (TextView) vg.getChildAt( 1 );
            tvText.setText( text );
            tvText.setTextColor( getResources().getColor( textColor ) );
            tvText.setVisibility( TextUtils.isEmpty( text ) ? GONE : VISIBLE );
        }
    }

    /**
     * 设置图文控件样式
     * @param tv        {@link TextView}
     * @param build     样式
     */
    private void setTextStyle(TextView tv, ItemStyleBuild build) {
        if( build == null ) return;
        int color = build.getTextColor();
        int gravity = build.getGravity();
        int bg = build.getBackgroundResource();
        int[] padding = build.getPadding();
        int iconPadding = build.getIconPadding();
        Typeface tf = build.getTypeface();

        tv.setTextSize( build.getTextSizeUnit(), build.getTextSize() );
        if( color != 0 ) tv.setTextColor( getResources().getColor( color ) );
        if( tf != null ) tv.setTypeface( tf );
        if( bg != 0 ) tv.setBackgroundResource( bg );
        tv.setGravity( gravity );
        if( padding != null ) tv.setPadding( padding[0], padding[1], padding[2], padding[3] );
        if( iconPadding != 0 ) tv.setCompoundDrawablePadding( iconPadding );
        tv.setIncludeFontPadding( build.isTextIncludeFontPadding() );
    }

    /**
     * 设置图标控件样式
     * @param iv        {@link ImageView}
     * @param build     样式
     */
    private void setImgStyle(ImageView iv, ItemStyleBuild build) {
        if( iv == null || build == null ) return;
        int bg = build.getBackgroundResource();
        int[] padding = build.getPadding();
        ViewGroup.LayoutParams lpImg = iv.getLayoutParams();
        lpImg.width = Utils.dp2Px( getContext(), build.getIconWidth() );
        lpImg.height = Utils.dp2Px( getContext(), build.getIconHeight() );
        if( bg != 0 ) iv.setBackgroundResource( bg );
        if( padding != null ) iv.setPadding( padding[0], padding[1], padding[2], padding[3] );
    }
}